//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using OpenLS.Chart;
using OpenLS.Core.Serialization;
using OpenLS.Spreadsheet.Expressions;

namespace OpenLS.Spreadsheet.Chart
{
    public class RangeNumericReference : NumericReference
    {
        public RangeNumericReference()
        {
        }
        public RangeNumericReference(Range range)
        {
            if (range == null)
                throw new ArgumentNullException("range");
            SetRange( range);
            
        }
        internal RangeNumericReference(EvaluationContext context, Expression expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");
            setRange(new InvalidRange(context, expression));
        }
        protected override void ReadXmlCore(ReadContext context)
        {
            using (ReadContext c = context.Read("numRef"))
            {

                string formula = c.ReadOptionalElementString("f");
                var workbook = context.GetData<Workbook>();
                var worksheet = context.GetData<Worksheet>();
                if (!string.IsNullOrEmpty(formula))
                    c.GetData<WorkbookResolver>().ResolveActions.Add
                        (
                        delegate
                            {
                                if (worksheet != null)
                                    setRange(new InvalidRange(worksheet, formula));
                                else
                                    setRange(new InvalidRange(workbook, formula));
                            });
                //\\ResolveReference(formula, ReadContextData.GetThemeOwner(context));
                Cache = c.ReadOptionalElementAs<NumericLiteral>("numCache");
                if (Cache != null)
                    Cache.Parent = this;
                Extension = c.ReadOptionalElement<ExtensionElement>("extLst");
            }
        }

        
        protected override void BuildCache()
        {
            Range r = InvalidRange.Range;
            if (r == null)
                return;
            Cache = new NumericLiteral();
            Cache.Parent = this;
            this.BeginEdit();
            foreach (Cell c in r.GetNonEmptyCells())
            {
                object v = c.Value;
                if (!(v is double))
                    continue;
                double dbl = (double)v;
                NumericValue nv = new NumericValue(this);
                nv.Value = dbl;
                nv.Index = r.GetCellIndex(c);
                Cache.AddValue(nv);
            }
            this.EndEdit();
            
        }

      

        internal NumericLiteral _numCache;

        private ExtensionElement _extension; //\\move up?

        public ExtensionElement Extension
        {
            get { return _extension; }
            set { _extension = value; }
        }

        internal void SetRange(EvaluationContext context, Expression range)
        {
            setRange(new InvalidRange(context, range));
        }
        internal void SetRange(Range range)
        {
            RangeReferenceExpression exp = new RangeReferenceExpression(range.ToReference(), range.Worksheet);
            setRange(new InvalidRange(new WorksheetEvaluationContext (range.Worksheet), exp));
        }

        private void setRange(InvalidRange range)
        {
            InvalidRange = range;
            if (range.Range == null)
                return;
            range.Range.CellValueChanged += range_CellValueChanged;
           // range.Range.Worksheet.CellValueChanged += range_CellValueChanged2;
         //   range.Range.Worksheet.Rows.
            NotifyPropertyChanged("Values");

        }


        public override IEnumerable<NumericValue> NumericValues
        {
            get
            {
                if (InvalidRange.Range == null)
                    yield break;
                foreach (Cell cell in InvalidRange.Range.GetNonEmptyCells())
                {
                    object value = cell.Value;
                    if (value is DateTime)
                        value = InvalidRange.Range.Worksheet.Workbook.ChangeType<double>(value);
                    if (value is double)
                    {
                        NumericValue v = new NumericValue(null)
                                             {
                                                 Index =
                                                     (cell.Row.Index - InvalidRange.Range.TopLeftCell.Row.Index) +
                                                     (cell.Column.Index - InvalidRange.Range.TopLeftCell.Column.Index),
                                                 Value = (double) value,
                                                 Parent = this
                                             };
                        yield return v;
                    }
                }
            }
        }
        public override sealed IEnumerable<object> Values
        {
            get
            {
                if (InvalidRange.Range == null)
                    yield break;
                foreach (Cell cell in InvalidRange.Range.GetNonEmptyCells())
                {
                    object value = cell.Value;
                    if (value is double)
                    {
                        NumericValue v = new NumericValue(null);
                        v.Index = (cell.Row.Index - InvalidRange.Range.TopLeftCell.Row.Index) + (cell.Column.Index - InvalidRange.Range.TopLeftCell.Column.Index);
                        v.Value = (double)value;
                        v.Parent = this;
                        yield return v;
                    }
                    if (value is DateTime)
                    {
                        DateValue v = new DateValue(
                        (cell.Row.Index - InvalidRange.Range.TopLeftCell.Row.Index) + (cell.Column.Index - InvalidRange.Range.TopLeftCell.Column.Index),
                        (DateTime)value);
                        yield return v;
                        
                    }
                }
            }
        }



        void range_CellValueChanged(object sender, EventArgs e)
        {
            OnValueChanged();
        }
        InvalidRange InvalidRange;

        public override string Formula
        {
            get
            {
                return InvalidRange.Formula;
            }
        }
    }
}
